let FlightPath = (function () {

    function FlightPath(viewer) {
        this.viewer = viewer;
    }

    FlightPath.prototype.start = function () {
        let viewer = this.viewer;

        //Set bounds of our simulation time
        let start = Cesium.JulianDate.fromDate(new Date(2024, 1, 22, 12));
        let stop = Cesium.JulianDate.addSeconds(start, 100, new Cesium.JulianDate());

        //Make sure viewer is at the desired time.
        viewer.clock.startTime = start.clone();
        viewer.clock.stopTime = stop.clone();
        viewer.clock.currentTime = start.clone();
        viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //在时间结束后再次从开始重复
        viewer.clock.multiplier = 1;//时间流速

        $(viewer.timeline.container).show();

        //Set timeline to simulation bounds
        viewer.timeline.zoomTo(start, stop);//底部时间条控件调整

        let viewModel = {
            rate: 5.0,
            gravity: 0.0,
            minimumLife: 1.0,
            maximumLife: 1.0,
            minimumSpeed: 5.0,
            maximumSpeed: 5.0,
            startScale: 30.0,
            endScale: 120.0,
            particleSize: 20.0,
            transX: 2.5,
            transY: 4.0,
            transZ: 1.0,
            heading: 0.0,
            pitch: 0.0,
            roll: 0.0,
            fly: false,
            spin: false,
            show: true
        };

        let entityPosition = new Cesium.Cartesian3();
        let entityOrientation = new Cesium.Quaternion();
        let rotationMatrix = new Cesium.Matrix3();
        let modelMatrix = new Cesium.Matrix4();

        function computeModelMatrix(entity, time) {
            let position = Cesium.Property.getValueOrUndefined(entity.position, time, entityPosition);
            if (!Cesium.defined(position)) {
                return undefined;
            }
            let orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, entityOrientation);
            if (!Cesium.defined(orientation)) {
                modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, modelMatrix);
            } else {
                modelMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, rotationMatrix), position, modelMatrix);
            }
            return modelMatrix;
        }

        let emitterModelMatrix = new Cesium.Matrix4();
        let translation = new Cesium.Cartesian3();
        let rotation = new Cesium.Quaternion();
        let hpr = new Cesium.HeadingPitchRoll();
        let trs = new Cesium.TranslationRotationScale();

        function computeEmitterModelMatrix() {
            hpr = Cesium.HeadingPitchRoll.fromDegrees(viewModel.heading, viewModel.pitch, viewModel.roll, hpr);

            trs.translation = Cesium.Cartesian3.fromElements(viewModel.transX, viewModel.transY, viewModel.transZ, translation);
            trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);

            return Cesium.Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix);
        }

        //计算运动轨迹函数：时间+位置
        function computeCirclularFlight(lon, lat, radius) {
            let property = new Cesium.SampledPositionProperty();
            for (let i = 0; i <= 360; i += 45) {
                let radians = Cesium.Math.toRadians(i);
                let time = Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());//时间递增
                let position = Cesium.Cartesian3.fromDegrees(lon + (radius * 1.5 * Math.cos(radians)), lat + (radius * Math.sin(radians)),
                    Cesium.Math.nextRandomNumber() * 500 + 1750);//位置变化
                property.addSample(time, position);
            }
            return property;
        }

        //计算模型随时间变化的位置
        //let circularPosition = computeCirclularFlight(117.16738, 31.8338, 200);
        let staticPosition = Cesium.Cartesian3.fromDegrees(117.16738, 31.8338, 200);//静止的位置

        let entity = viewer.entities.add({

            //Set the entity availability to the same interval as the simulation time.
            availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
                start: start,
                stop: stop
            })]),

            //Load the Cesium plane model to represent the entity
            model: {
                uri: baseUrl + '/gltf/floor/' + 1 + '.glb',
                // color: getColor('red', 1),
                minimumPixelSize: 54,//控制模型最小
                maximumScale: 5//控制模型最大
            },

            position: staticPosition,

            //实时轨迹显示
            path: {
                show: true,
                leadTime: 0,//飞机将要经过的路径，路径存在的时间
                trailTime: 60,//飞机已经经过的路径，路径存在的时间
                width: 1,//线宽度
                resolution: 1,
                material: new Cesium.PolylineGlowMaterialProperty({
                    glowPower: 0.3,//应该是轨迹线的发光强度
                    color: Cesium.Color.PALEGOLDENROD//颜色
                })
            }
        });

        viewer.trackedEntity = entity;
        function getColor(colorName, alpha) {
            let color = Cesium.Color[colorName.toUpperCase()];
            return Cesium.Color.fromAlpha(color, parseFloat(alpha));
        }
        //根据geojson获取飞行路径
        let property = new Cesium.SampledPositionProperty();
        let lat = 31.8338;
        for (let i = 0; i < 10; i++) {
            let dtime = 10 * i;
            let lng = 117.16738 + 0.01 * i;
            if (i > 5) lat -= 0.01;
            let time = Cesium.JulianDate.addSeconds(start, dtime, new Cesium.JulianDate());//时间递增
            let position = Cesium.Cartesian3.fromDegrees(lng, lat, 200);//位置变化
            property.addSample(time, position);
        }

        entity.position = property;
        entity.orientation = new Cesium.VelocityOrientationProperty(property);
        //移动的原理：position参数包含时间和所处位置，根据当前时间得到位置
        //entity.position = circularPosition;
        //根据模型当前位置自动计算模型的旋转等参数
        //entity.orientation = new Cesium.VelocityOrientationProperty(circularPosition);


        /*************************
        粒子系统实现
        **************************/
        let scene = viewer.scene;
        //粒子系统初始化-实际是使用图片，改变图片的显示样式实现仿粒子化。
        //图片可以利用canvas代替，在canvas中可以绘制自定义图形
        let particleSystem = scene.primitives.add(new Cesium.ParticleSystem({
            image: baseUrl + '/images/fire.png',

            startColor: Cesium.Color.RED.withAlpha(0.7),
            endColor: Cesium.Color.YELLOW.withAlpha(0.3),

            startScale: viewModel.startScale,
            endScale: viewModel.endScale,

            minimumLife: viewModel.minimumLife,
            maximumLife: viewModel.maximumLife,

            minimumSpeed: viewModel.minimumSpeed,
            maximumSpeed: viewModel.maximumSpeed,

            minimumWidth: viewModel.particleSize,
            minimumHeight: viewModel.particleSize,

            maximumWidth: viewModel.particleSize,
            maximumHeight: viewModel.particleSize,

            // Particles per second.
            rate: viewModel.rate,

            bursts: [
                new Cesium.ParticleBurst({ time: 5.0, minimum: 2, maximum: 5 }),
                new Cesium.ParticleBurst({ time: 10.0, minimum: 2, maximum: 5 }),
                new Cesium.ParticleBurst({ time: 15.0, minimum: 2, maximum: 5 })
            ],

            lifeTime: 16.0,

            emitter: new Cesium.CircleEmitter(0.5),

            emitterModelMatrix: computeEmitterModelMatrix(),

            forces: [applyGravity]
        }));
        particleSystem.show = true;//不显示粒子系统
        //粒子系统重力
        let gravityScratch = new Cesium.Cartesian3();
        function applyGravity(p, dt) {
            // We need to compute a local up vector for each particle in geocentric space.
            let position = p.position;

            Cesium.Cartesian3.normalize(position, gravityScratch);
            Cesium.Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch);

            p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
        }
        //根据目标模型计算粒子系统相关参数
        viewer.scene.preRender.addEventListener(function (scene, time) {
            particleSystem.modelMatrix = computeModelMatrix(entity, time);
            // Account for any changes to the emitter model matrix.
            particleSystem.emitterModelMatrix = computeEmitterModelMatrix();

        });
    }

    return FlightPath;
})();
